// share_state use : Arc<Mutex<Data>> between threads (tasks)
#[cfg(test)] 
mod test {
    //channel in tokio
    // one shot : single-producer, single-consumer; 
    //      only one value can be sent in lifetime of the oneshot channel
    // mpsc     : multi-producer, single-consumuer;   
    //      many values can be sent
    // broadcast: multi-producer, multi-consumer channel, 
    //      Many values can be sent, each recv sees every value
    // watch  single-producer, multi-consumer 
    //      Many values can be sent, but no history is kept. recv only see the most recent value
    // async_channel -> multi-producer, multi-consumer
    //      each message can be recved by only one of all existing consumers

    //sending a [single value] from a [single] producer to a [single] consumer.
    #[tokio::test(flavor = "multi_thread")]
    async fn oneshot(){
        use tokio::sync::oneshot;
        //use tokio::time::{sleep, Duration};
        let (tx, rx) = oneshot::channel();

        tokio::spawn(async move {
            //sleep(Duration::from_secs(1)).await;
            tx.send(10).unwrap(); // send(mut self, t) => oneshot
        });

        
        let res = rx.await.unwrap();
        assert_eq!(10, res);
    }

    //sending [many values] from a [single] producers to a [single] consumer. 
    #[tokio::test(flavor = "multi_thread")]
    async fn mpsc_many_value_in_single_sender(){
        use tokio::sync::mpsc;
        let (tx, mut rx) = mpsc::channel(100);

        tokio::spawn(async move {
            for i in 0..10 {
                tx.send(i).await.unwrap();
            }
        });

        while let Some(res) = rx.recv().await {
            println!("{res}");
        }
    }

    //sending [many values] from [many] producers to a [single] consumer. 
    #[tokio::test(flavor = "multi_thread")]
    async fn mpsc() {
        use tokio::sync::mpsc;
        let (tx, mut rx) = mpsc::channel(100);
        for i in 0..10 {
            let tx = tx.clone();
            tokio::spawn( async move {
                tx.send(i).await.unwrap();
            });
        }

        // rx return None once all tx clones drop
        drop(tx);

        // rx.recv only return None if all tx.clones are droped
        while let Some(res) = rx.recv().await { // will be wait here forever if no drop(tx) in main-thread
            println!("{res}");
        }
    }

    //sending [many values] from [many] producers to [many] consumers
    //Each consumer will receive each value
    #[tokio::test(flavor = "multi_thread")]
    async fn broadcast() {
        let (tx, mut rx1) = tokio::sync::broadcast::channel(16);
       
        tokio::spawn( async move {
            assert_eq!(rx1.recv().await.unwrap(), 10);
            assert_eq!(rx1.recv().await.unwrap(), 20);
        });

        let mut rx2 = tx.subscribe();
        tokio::spawn( async move {
            assert_eq!(rx2.recv().await.unwrap(), 10);
            assert_eq!(rx2.recv().await.unwrap(), 20);
        });

        tx.send(10).unwrap();
        tx.send(20).unwrap();
    }


    //sending [many values] from a [single] producer to [many] consumers.
    // sender::new(init) && recver::new(init); 
    // sender.send(new_value);  
    //
    // recver.borrow();
    // recver.borrow_and_update();
    #[tokio::test(flavor = "multi_thread")]
    #[ignore]
    async fn watch_borrow() {
        let init_value = 10;
        let (tx, mut rx) = tokio::sync::watch::channel(init_value);
        //init watch channel -> 1. no changed 2. borrow init_value && seen state
            

        //init_value with seen
        assert!(false == rx.has_changed().unwrap());
        assert_eq!(*(rx.borrow()), init_value);
        assert!(false == rx.has_changed().unwrap());
        assert_eq!(*(rx.borrow()), init_value);
        assert!(false == rx.has_changed().unwrap());
        assert_eq!(*(rx.borrow_and_update()), init_value);
        assert!(false == rx.has_changed().unwrap());
        assert_eq!(*(rx.borrow_and_update()), init_value);


        tx.send(20).unwrap(); // new_value to channel with unseen
        for _ in 0..4 {
            let mut rx = rx.clone();
            tokio::spawn(async move {
                //TODO: assert!(false == rx.has_changed().unwrap());
                rx.changed().await.unwrap();
                assert!(false == rx.has_changed().unwrap());
                assert_eq!(*rx.borrow_and_update(), 20);
            });
        }
    }
}
